package com.group.a.server;

import com.group.a.buffer.ReadWriteBuffer;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;

public class NioServer implements Runnable{
    private Integer port;
    private static final int DEFAULT_PORT = 8888;

    public NioServer(Integer port) {
        if (port == null){
            this.port = DEFAULT_PORT;
        }else {
            this.port = port;
        }
    }

    public NioServer() {
        this.port = DEFAULT_PORT;
    }

    public static void main(String[] args) {
        Thread thread = new Thread(new NioServer());
        thread.start();
        try {
            Thread.sleep(600000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread.interrupt();
    }

    @Override
    public void run() {
        ServerSocketChannel serverSC = null;
        try {
            //构建服务端socket通道对象
            serverSC = ServerSocketChannel.open();
            //配置为非阻塞
            serverSC.configureBlocking(false);
            //socket-server绑定端口
            serverSC.bind(new InetSocketAddress(this.port));
            //构建事件选择器对象
            Selector selector = Selector.open();
            //通道对象注册accept事件
            serverSC.register(selector,SelectionKey.OP_ACCEPT);
            //运行线程不被中断
            while (!Thread.currentThread().isInterrupted()){
                //事件选择器中监听到事件
                if (selector.select() == 0)continue;
                    Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                    while (iterator.hasNext()){
                        SelectionKey key = iterator.next();
                        iterator.remove();
                        //accpet事件
                        if (key.isAcceptable()){
                            System.out.println("轮询到accept事件");
                            //接入
                            SocketChannel socketChl = serverSC.accept();
                            socketChl.configureBlocking(false);
                            //注册可读事件
                            socketChl.register(selector,SelectionKey.OP_READ,new ReadWriteBuffer());
                            System.out.println("accept from " + socketChl.getRemoteAddress());
                        }
                        if (key.isReadable()){
                            System.out.println("轮询到read事件");
                            ReadWriteBuffer rwBuffer = (ReadWriteBuffer) key.attachment();
                            ByteBuffer readBuffer = rwBuffer.getReadBuffer();
                            ByteBuffer writeBuffer = rwBuffer.getWriteBuffer();

                            SocketChannel sc = (SocketChannel) key.channel();
                            //读取
                            sc.read(readBuffer);
                            readBuffer.flip();

                            //解码
                            Charset charset = Charset.forName("UTF-8");
                            CharBuffer charBuffer = charset.decode(readBuffer);
                            System.out.println("from client:"+new String(charBuffer.array()));
                            readBuffer.rewind();
                            readBuffer.clear();

                            //回复
                            writeBuffer.put("hi,client!".getBytes());

                            //添加感兴趣的事件
                            key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
                        }
                        if (key.isWritable()){
                            System.out.println("轮询到write事件");
                            ReadWriteBuffer rwBuffer = (ReadWriteBuffer) key.attachment();
                            ByteBuffer writeBuffer = rwBuffer.getWriteBuffer();
                            //position、limit反转
                            writeBuffer.flip();
                            SocketChannel sc = (SocketChannel) key.channel();
                            int len = 0;
                            //buffer中还有剩余的
                            while (writeBuffer.hasRemaining()){
                                //空闲长度
                                len = sc.write(writeBuffer);
                                //已写满
                                if(len == 0){
                                    break;
                                }
                            }
                            //压缩
                            writeBuffer.compact();
                            if (len != 0){
                                /*取消通道的写事件*/
                                key.interestOps(key.interestOps() & (~SelectionKey.OP_WRITE));
                            }
                        }
                    }
                }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if (serverSC != null){
                    serverSC.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
